package com.snts.synchronization.core;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Synchronization {

	boolean externalUpdateWins = true;
	private List<SyncTable> tables = new ArrayList<SyncTable>();

	private Map<ExternalTable, SyncTable> tablesByExternalName = new HashMap<ExternalTable, SyncTable>();

	private String pkColumnName = "id";
	private boolean updateAppendsLog = false;
	private boolean quoteIdentifier = false;

	public boolean isExternalUpdateWins() {
		return externalUpdateWins;
	}

	public void setExternalUpdateWins(boolean externalUpdateWins) {
		this.externalUpdateWins = externalUpdateWins;
	}

	public List<SyncTable> getTables() {
		return tables;
	}
	
	void addTable(SyncTable t){
		t.synchronization = this;
		tables.add(t);
		tablesByExternalName.put(t.getExternalTable(), t);
	}
	
	public Synchronization load(DatabaseMetaData metadata){
		// First load from XML
		new XMLLoader(this).load();
		// Enrich XML configuration from database
		for(SyncTable t : tables){
			try {
				ResultSet rs = metadata.getColumns(null, t.schema, t.name, null);
				System.out.println("Configuring column types...");
				try{
					while(rs.next()){
						String columnName = rs.getString("COLUMN_NAME");
						System.out.println("Column - \"" + columnName + "\"");
						t.configureColumn(columnName, rs);
					}
				} finally {
					rs.close();
				}
			} catch (SQLException e) {
				e.printStackTrace();
				throw new RuntimeException("SQLException loading schema from database for table[" + t.schema + "." + t.name + "]", e);
			}
		}
		return this;
	}
	
	public String getPkColumnName() {
		return pkColumnName;
	}

	public void setPkColumnName(String pkColumnName) {
		this.pkColumnName = pkColumnName;
	}
	
	public boolean isUpdateAppendsLog() {
		return updateAppendsLog;
	}

	public void setUpdateAppendsLog(boolean updateAppendsLog) {
		this.updateAppendsLog = updateAppendsLog;
	}

	public static void main(String[] args) throws SQLException, ClassNotFoundException{
		Synchronization synchronization = new Synchronization();
		Class.forName("org.postgresql.Driver");
		Connection conn = DriverManager.getConnection(
				"jdbc:postgresql://127.0.0.1:5432/Restaurant", "postgres",
				"123");		
		synchronization.load(conn.getMetaData());
		for(SyncTable t : synchronization.getTables()){
			System.out.println("<table name=" + t.name + ">");
			System.out.println("  <join-route>");
			for (TableReference jri : t.joinRoute) {
				System.out
						.println("        <join-route-item tableName=" + jri.getTableName() + " joinColumn=" + jri.getForeignKey() + "/>");
			}
			System.out.println("  </join-route>");
			for(Column c : t.getColumns()){
				System.out.println("    <column name=" + c.name + " external-name=" + c.externalName + " external-table-name=" 
			                                           + c.externalTableName + " sync-direction=" + c.syncDirection.name() + " />");
			}
		}
	}
	
	public void setQuoteIdentifier(boolean quoteIdentifier) {
		this.quoteIdentifier = quoteIdentifier;
	}

	public boolean isQuoteIdentifier() {
		return quoteIdentifier;
	}
	
	public SyncTable getTableByExternalName(ExternalTable externalName){
		return tablesByExternalName.get(externalName);
	}
	
}
